package com.yc.testupload;

import org.apache.poi.xwpf.usermodel.*;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STHighlightColor;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STShd;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTRPr;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTc;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTcPr;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTShd;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 带有代码高亮功能的Word文档生成器
 * 用于生成包含语法高亮代码块的Word文档
 */
public class HighlightedCodeWordGenerator {

    /**
     * 生成带有代码高亮的Word文档
     * @param title 文档标题
     * @param content 文档内容，支持Markdown格式的代码块
     * @param outputPath 输出文件路径
     * @throws IOException 文件操作异常
     */
    public void generateWordWithCodeHighlighting(String title, String content, String outputPath) throws IOException {
        // 创建新的Word文档
        XWPFDocument document = new XWPFDocument();
        
        // 设置文档标题
        XWPFParagraph titleParagraph = document.createParagraph();
        titleParagraph.setAlignment(ParagraphAlignment.CENTER);
        
        XWPFRun titleRun = titleParagraph.createRun();
        titleRun.setText(title);
        titleRun.setBold(true);
        titleRun.setFontSize(18);
        
        // 添加一个空行
        document.createParagraph();
        
        // 处理内容，识别代码块并添加到文档
        processContentWithCodeBlocks(document, content);
        
        // 保存文档
        try (FileOutputStream out = new FileOutputStream(outputPath)) {
            document.write(out);
        } finally {
            document.close();
        }
        
        System.out.println("带有代码高亮的Word文档已生成：" + outputPath);
    }
    
    /**
     * 处理内容，识别代码块并添加到文档
     * @param document Word文档对象
     * @param content 文档内容
     */
    private void processContentWithCodeBlocks(XWPFDocument document, String content) {
        // 识别并处理多行代码块（```code``` 格式）
        Pattern codeBlockPattern = Pattern.compile("```([\\s\\S]*?)```");
        Matcher matcher = codeBlockPattern.matcher(content);
        int lastIndex = 0;
        
        while (matcher.find()) {
            // 添加代码块之前的内容
            if (matcher.start() > lastIndex) {
                addTextContent(document, content.substring(lastIndex, matcher.start()));
            }
            
            // 添加高亮的代码块
            String codeContent = matcher.group(1);
            addHighlightedCodeBlock(document, codeContent);
            
            lastIndex = matcher.end();
        }
        
        // 添加剩余内容
        if (lastIndex < content.length()) {
            addTextContent(document, content.substring(lastIndex));
        }
    }
    
    /**
     * 添加普通文本内容到文档
     * @param document Word文档对象
     * @param text 文本内容
     */
    private void addTextContent(XWPFDocument document, String text) {
        // 处理行内代码（`code` 格式）
        Pattern inlineCodePattern = Pattern.compile("`([^`]+)`");
        Matcher inlineMatcher = inlineCodePattern.matcher(text);
        int lastIndex = 0;
        
        XWPFParagraph paragraph = document.createParagraph();
        
        while (inlineMatcher.find()) {
            // 添加行内代码之前的文本
            if (inlineMatcher.start() > lastIndex) {
                String normalText = text.substring(lastIndex, inlineMatcher.start());
                addNormalText(paragraph, normalText);
            }
            
            // 添加行内代码
            String inlineCode = inlineMatcher.group(1);
            addInlineCode(paragraph, inlineCode);
            
            lastIndex = inlineMatcher.end();
        }
        
        // 添加剩余的普通文本
        if (lastIndex < text.length()) {
            String remainingText = text.substring(lastIndex);
            addNormalText(paragraph, remainingText);
        }
    }
    
    /**
     * 添加普通文本到段落
     * @param paragraph 段落对象
     * @param text 文本内容
     */
    private void addNormalText(XWPFParagraph paragraph, String text) {
        // 按行分割文本
        String[] lines = text.split("\\n");
        
        for (int i = 0; i < lines.length; i++) {
            if (i > 0) {
                // 为每行创建新段落
                paragraph = paragraph.getDocument().createParagraph();
            }
            
            String line = lines[i];
            
            // 检测是否为问题或答案行
            if (line.trim().startsWith("问题") || 
                line.trim().matches("^\\d+\\.\\s*问题") || 
                line.trim().matches("^\\d+\\.\\s*题目") ||
                line.trim().matches("^问题\\d+：")) {
                // 添加问题格式的文本
                XWPFRun run = paragraph.createRun();
                run.setText(line);
                run.setBold(true);
                run.setColor("2c3e50");
                run.setFontSize(12);
            } else if (line.trim().startsWith("答案") || line.trim().startsWith("解析")) {
                // 添加答案格式的文本
                XWPFRun run = paragraph.createRun();
                run.setText(line);
                run.setColor("34495e");
                run.setFontSize(12);
            } else {
                // 添加普通文本
                XWPFRun run = paragraph.createRun();
                run.setText(line);
                run.setFontSize(12);
            }
        }
    }
    
    /**
     * 添加行内代码到段落
     * @param paragraph 段落对象
     * @param code 代码内容
     */
    private void addInlineCode(XWPFParagraph paragraph, String code) {
        XWPFRun run = paragraph.createRun();
        run.setText(code);
        run.setFontFamily("Courier New");
        run.setFontSize(11);
        
        // 设置行内代码的样式（浅灰色背景）
        CTRPr rPr = run.getCTR().addNewRPr();
        rPr.addNewHighlight().setVal(STHighlightColor.WHITE);
        // 直接添加新的Shd元素，不使用getShd()方法
        CTShd shd = rPr.addNewShd();
        shd.setFill("F5F5F5");
        shd.setVal(STShd.CLEAR);
    }
    
    /**
     * 添加高亮的代码块到文档
     * @param document Word文档对象
     * @param code 代码内容
     */
    private void addHighlightedCodeBlock(XWPFDocument document, String code) {
        // 设置代码块样式（创建带有浅灰色背景的文本框效果）
        // 在Word中，我们使用表格来模拟代码块的容器效果
        XWPFTable table = document.createTable(1, 1);
        XWPFTableRow row = table.getRow(0);
        XWPFTableCell cell = row.getCell(0);
        
        // 设置单元格背景色为浅灰色
        CTTc tc = cell.getCTTc();
        CTTcPr tcPr = tc.getTcPr();
        if (tcPr == null) {
            tcPr = tc.addNewTcPr();
        }
        // 直接添加新的Shd元素，不使用getShd()方法
        CTShd shd = tcPr.addNewShd();
        shd.setFill("F5F5F5"); // 设置为浅灰色背景
        
        // 添加代码内容到单元格
        XWPFParagraph cellParagraph = cell.getParagraphArray(0);
        if (cellParagraph == null) {
            cellParagraph = cell.addParagraph();
        }
        
        // 应用语法高亮并添加代码到段落
        applyBasicSyntaxHighlighting(cellParagraph, code);
        
        // 添加一个空行作为代码块后的间距
        document.createParagraph();
    }
    
    /**
     * 应用基本的语法高亮
     * @param paragraph 段落对象
     * @param code 代码内容
     */
    private void applyBasicSyntaxHighlighting(XWPFParagraph paragraph, String code) {
        // 定义常见编程语言的关键字（Java、JavaScript等通用关键字）
        String[] keywords = {
            "abstract", "assert", "boolean", "break", "byte", "case", "catch", "char", "class", "const",
            "continue", "default", "do", "double", "else", "enum", "extends", "final", "finally", "float",
            "for", "goto", "if", "implements", "import", "instanceof", "int", "interface", "long", "native",
            "new", "package", "private", "protected", "public", "return", "short", "static", "strictfp", "super",
            "switch", "synchronized", "this", "throw", "throws", "transient", "try", "void", "volatile", "while",
            "true", "false", "null", "function", "var", "let", "const", "async", "await", "yield"
        };
        
        // 定义正则表达式来匹配不同的代码元素
        // 1. 注释（// 单行注释）
        // 2. 多行注释（/* */）
        // 3. 字符串（"..." 或 '...'）
        // 4. 关键字
        // 5. 数字
        
        // 按行处理代码
        String[] lines = code.split("\\n");
        boolean inMultiLineComment = false;
        StringBuilder lineBuilder = new StringBuilder();
        
        for (int lineIndex = 0; lineIndex < lines.length; lineIndex++) {
            String line = lines[lineIndex];
            
            // 处理行时需要考虑多行注释的情况
            if (inMultiLineComment) {
                int endCommentIndex = line.indexOf("*/");
                if (endCommentIndex != -1) {
                    // 多行注释结束
                    addCommentText(paragraph, lineBuilder.toString() + line.substring(0, endCommentIndex + 2));
                    line = line.substring(endCommentIndex + 2);
                    inMultiLineComment = false;
                    lineBuilder.setLength(0);
                } else {
                    // 多行注释继续
                    lineBuilder.append(line).append("\n");
                    continue;
                }
            }
            
            // 处理行内的各种元素
            int pos = 0;
            while (pos < line.length()) {
                // 检查是否是注释开始
                if (line.startsWith("//", pos)) {
                    // 添加注释前的普通文本
                    if (pos > 0) {
                        processCodeSegment(paragraph, line.substring(0, pos), keywords);
                    }
                    // 添加注释
                    addCommentText(paragraph, line.substring(pos));
                    pos = line.length();
                } 
                // 检查是否是多行注释开始
                else if (line.startsWith("/*", pos)) {
                    int endIndex = line.indexOf("*/", pos);
                    if (endIndex != -1) {
                        // 单行内的多行注释
                        if (pos > 0) {
                            processCodeSegment(paragraph, line.substring(0, pos), keywords);
                        }
                        addCommentText(paragraph, line.substring(pos, endIndex + 2));
                        pos = endIndex + 2;
                    } else {
                        // 跨行的多行注释开始
                        if (pos > 0) {
                            processCodeSegment(paragraph, line.substring(0, pos), keywords);
                        }
                        lineBuilder.append(line.substring(pos)).append("\n");
                        inMultiLineComment = true;
                        pos = line.length();
                    }
                } 
                // 检查是否是字符串开始
                else if (line.charAt(pos) == '"') {
                    // 添加字符串前的普通文本
                    if (pos > 0) {
                        processCodeSegment(paragraph, line.substring(0, pos), keywords);
                    }
                    // 查找字符串结束位置，需要考虑转义字符
                    int endIndex = findStringEnd(line, pos + 1, '"');
                    if (endIndex != -1) {
                        addStringText(paragraph, line.substring(pos, endIndex + 1));
                        pos = endIndex + 1;
                    } else {
                        // 未闭合的字符串，作为普通文本处理
                        processCodeSegment(paragraph, line.substring(pos), keywords);
                        pos = line.length();
                    }
                } 
                // 检查是否是字符开始
                else if (line.charAt(pos) == '\'') {
                    // 添加字符前的普通文本
                    if (pos > 0) {
                        processCodeSegment(paragraph, line.substring(0, pos), keywords);
                    }
                    // 查找字符结束位置，需要考虑转义字符
                    int endIndex = findStringEnd(line, pos + 1, '\'');
                    if (endIndex != -1) {
                        addStringText(paragraph, line.substring(pos, endIndex + 1));
                        pos = endIndex + 1;
                    } else {
                        // 未闭合的字符，作为普通文本处理
                        processCodeSegment(paragraph, line.substring(pos), keywords);
                        pos = line.length();
                    }
                } 
                // 如果到达行尾，处理剩余文本
                else if (pos == line.length() - 1) {
                    processCodeSegment(paragraph, line.substring(pos), keywords);
                    pos = line.length();
                } else {
                    pos++;
                }
            }
            
            // 如果不是最后一行，添加换行
            if (lineIndex < lines.length - 1) {
                addNormalCodeText(paragraph, "\n");
            }
        }
    }
    
    /**
     * 处理代码片段，识别关键字和数字
     */
    private void processCodeSegment(XWPFParagraph paragraph, String text, String[] keywords) {
        // 简单的分词处理
        Pattern pattern = Pattern.compile("([a-zA-Z_$][a-zA-Z0-9_$]*|\\d+\\.?\\d*[fFlL]?|\\S)");
        Matcher matcher = pattern.matcher(text);
        int lastEnd = 0;
        
        while (matcher.find()) {
            // 添加非匹配部分（通常是空白字符）
            if (matcher.start() > lastEnd) {
                addNormalCodeText(paragraph, text.substring(lastEnd, matcher.start()));
            }
            
            String token = matcher.group(1);
            
            // 检查是否是关键字
            boolean isKeyword = false;
            for (String keyword : keywords) {
                if (keyword.equals(token)) {
                    isKeyword = true;
                    break;
                }
            }
            
            if (isKeyword) {
                // 关键字 - 蓝色
                addKeywordText(paragraph, token);
            } 
            // 检查是否是数字
            else if (token.matches("\\d+\\.?\\d*[fFlL]?")) {
                // 数字 - 绿色
                addNumberText(paragraph, token);
            } else {
                // 普通代码文本
                addNormalCodeText(paragraph, token);
            }
            
            lastEnd = matcher.end();
        }
        
        // 添加剩余部分
        if (lastEnd < text.length()) {
            addNormalCodeText(paragraph, text.substring(lastEnd));
        }
    }
    
    /**
     * 查找字符串结束位置，考虑转义字符
     */
    private int findStringEnd(String text, int start, char delimiter) {
        boolean escaped = false;
        for (int i = start; i < text.length(); i++) {
            if (text.charAt(i) == '\\' && !escaped) {
                escaped = true;
            } else if (text.charAt(i) == delimiter && !escaped) {
                return i;
            } else {
                escaped = false;
            }
        }
        return -1; // 未找到闭合的分隔符
    }
    
    /**
     * 添加普通代码文本
     */
    private void addNormalCodeText(XWPFParagraph paragraph, String text) {
        XWPFRun run = paragraph.createRun();
        run.setText(text);
        run.setFontFamily("Courier New");
        run.setFontSize(10);
    }
    
    /**
     * 添加关键字文本（蓝色）
     */
    private void addKeywordText(XWPFParagraph paragraph, String text) {
        XWPFRun run = paragraph.createRun();
        run.setText(text);
        run.setFontFamily("Courier New");
        run.setFontSize(10);
        run.setColor("0000FF"); // 蓝色
        run.setBold(true);
    }
    
    /**
     * 添加字符串文本（绿色）
     */
    private void addStringText(XWPFParagraph paragraph, String text) {
        XWPFRun run = paragraph.createRun();
        run.setText(text);
        run.setFontFamily("Courier New");
        run.setFontSize(10);
        run.setColor("008000"); // 绿色
    }
    
    /**
     * 添加数字文本（紫色）
     */
    private void addNumberText(XWPFParagraph paragraph, String text) {
        XWPFRun run = paragraph.createRun();
        run.setText(text);
        run.setFontFamily("Courier New");
        run.setFontSize(10);
        run.setColor("800080"); // 紫色
    }
    
    /**
     * 添加注释文本（灰色）
     */
    private void addCommentText(XWPFParagraph paragraph, String text) {
        XWPFRun run = paragraph.createRun();
        run.setText(text);
        run.setFontFamily("Courier New");
        run.setFontSize(10);
        run.setColor("808080"); // 灰色
        run.setItalic(true);
    }
    
    /**
     * 清理HTML标签，只保留纯文本内容
     * @param html HTML内容
     * @return 纯文本内容
     */
    private String cleanHtml(String html) {
        if (html == null || html.isEmpty()) {
            return "";
        }
        // 简单的HTML清理，移除标签，保留文本内容
        return html.replaceAll("<[^>]*>", "").trim();
    }
    
    /**
     * 转义特殊字符
     * @param text 文本内容
     * @return 转义后的文本
     */
    private String escapeHtml(String text) {
        if (text == null) return "";
        return text
            .replace("&", "&amp;")
            .replace("<", "&lt;")
            .replace(">", "&gt;")
            .replace("\"", "&quot;")
            .replace("'", "&#39;");
    }
}